package com.airbat.prize.utils;

import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.Digester;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ObjectUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

@Slf4j
public class CheckSumUtil {
    private static final String ENCRYPT_KEY = "appSecret";

    private static final Set<String> IGNORE_SORT_FIELDS = Sets.newHashSet("appSecret", "checkSum");

    /**
     * @description: checkSum生成
     * @author: ZhangPengJu
     * @create: 2023/3/28 17:18
     * @version: 1.0.0
     **/
    public static String checkSumGe(Map<String, Object> originDataMap) {
        String encryptKey = ObjectUtils.toString(originDataMap.get(ENCRYPT_KEY));
        //获取数据的键，并进行字典升序
        TreeSet<String>treeSet = new TreeSet<>();
        originDataMap.forEach((k, v) -> {
            //排除checkSum 这个校验字段
            if (!isInIgnoreFields(k)) {
                treeSet.add(k);
            }
        });
        //进行键值拼接如id123456numIdstring
        StringBuilder contactStrVal = new StringBuilder();
        treeSet.forEach((k) -> {
            contactStrVal.append(k).append(originDataMap.get(k));
        });
        //在最后拼接秘钥
        contactStrVal.append(encryptKey);
        Digester md5 = new Digester(DigestAlgorithm.MD5);
        return md5.digestHex(String.valueOf(contactStrVal));
    }

    /**
     * 默认使用md5进行加密
     *
     * @param originDataMap
     * @return
     */
    public static boolean vaCheckSum(Map<String, Object>originDataMap) {
        String encryptKey = originDataMap.get(ENCRYPT_KEY).toString();
        //获取数据的键，并进行字典升序
        TreeSet<String>treeSet = new TreeSet<>();
        originDataMap.forEach((k, v) -> {

            if (!isInIgnoreFields(k)) {
                treeSet.add(k);
            }
        });

        //进行键值拼接如id123456numIdstring
        StringBuilder contactStrVal = new StringBuilder();
        treeSet.forEach((k) -> {
            contactStrVal.append(k).append(originDataMap.get(k));
        });
        //在最后拼接秘钥
        contactStrVal.append(encryptKey);

        //日志中传入的校验码
        String checkSum = String.valueOf(originDataMap.get("checkSum"));

        return checkSumByEncryptMethod(checkSum, contactStrVal.toString());
    }

    private static boolean checkSumByEncryptMethod(String checkSum, String contactStrVal) {
        Digester md5 = new Digester(DigestAlgorithm.MD5);
        String digestHex = md5.digestHex(contactStrVal);
        //判断日志是否被修改过
        log.debug("应用日志的checksum校验工具类-计算得出的checkSum:{}", digestHex);
        log.debug("应用日志的checksum校验工具类-计算得出的checkSum:{}", digestHex);
        log.debug("第三方计算得到的checkSum:{}", checkSum);
        log.debug("应用日志的checksum校验工具类-键值拼接后的字符串:{}", contactStrVal);
        return digestHex.equalsIgnoreCase(checkSum);
    }

    private static boolean isInIgnoreFields(String field) {
        for (String ignoreField : IGNORE_SORT_FIELDS) {
            if (field.equalsIgnoreCase(ignoreField)) {
                return true;
            }
        }
        return false;
    }

    //测试
    public static void main(String[] args) {
        //logs中字段map
        Map<String, Object>logsmap = new HashMap<>();
        logsmap.put("numId", "string");
        logsmap.put("userId", "string");
        logsmap.put("userName", "string");
        logsmap.put("organization", "string");
        logsmap.put("organizationId", "string");
        logsmap.put("operateTime", "string");
        logsmap.put("terminalId", "string");
        logsmap.put("operateType", "string");
        logsmap.put("operateResult", "string");
        logsmap.put("errorCode", "string");
        logsmap.put("operateName", "string");
        logsmap.put("operateCondition", "string");
        logsmap.put("display", "3335sadf");
        logsmap.put("dataLevel", "01");

//        包含所有字段的map
        Map<String, Object>parentMap = new HashMap<>();
        parentMap.put("regId", "440133155");
        parentMap.put("sendId", "1380113614545");
        parentMap.put("logType", "1");
        parentMap.put("logs", logsmap);
        parentMap.put("appSecret", "0b14ed8ba69a670b098661fec902845a");

//        校验map
        logsmap.put("regId", parentMap.get("regId"));
        logsmap.put("sendId", parentMap.get("sendId"));
        logsmap.put("logType", parentMap.get("logType"));
        logsmap.put("appSecret", parentMap.get("appSecret"));
        logsmap.put("checkSum", CheckSumUtil.checkSumGe(logsmap));

        boolean checkSum = CheckSumUtil.vaCheckSum(logsmap);
        if (checkSum) {
            System.out.println("checkSum 校验通过");
        }
        if (!checkSum) {
            System.out.println("checkSum 校验未通过");
        }
    }

}
